
class ContentTemplate < ContainerThing

  Event.on('app:init') {
    begin
      ContentTemplate.all.each { |template|
        template.establish_class
      }
    rescue
    end
  }

  property :template_title, String
  property :template_class, String

  def initialize *a
    super
    #show_window false
    can_move false
  end

  def save *a
    if template_class
      establish_class
    end
    super
  end

  def children_creators e
    children.map {|ch|
      if use_meta_creator ch
        ch.creator_window(e, ch.meta_creator(e)).to_s
      else
        ch.creator_window(e).to_s
      end
    }.join
  end

  def content_children
    children.select {|ch|
      (ch.respond_to?(:name) && (!['template_class', 'template_title'].include? ch.name)) &&
         (ch.respond_to? :meta_creator)
    }
  end

  def use_meta_creator child
    (child.respond_to? :name) &&
      !(['template_class', 'template_title'].include? child.name) &&
        (child.respond_to? :meta_creator)
  end


  def thingswecanadd
    [TextThing, StringField, IntegerField, TextField, PlaceField, TemplateThing, NamedContainer, NamedDecorator]
  end

  def default_template
    title = StringField.new(:template_title)
    title.caption = "název"
    title.child = InputThing.new
    add title
    klass = StringField.new(:template_class)
    klass.caption = "třída"
    klass.child = InputThing.new
    add klass
  end
  
  def clone_thing
    #start with our own data
    hash = to_hash

    # remove template class and name
    hash['children'] = content_children.map(&:to_hash)
    #hash['children'].shift

    # change class into target class
    hash['thing'] = template_class

    #remove identity and version
    hash['identity'] = nil
    hash['version'] = nil

    # instantiate template
    Thing.from_hash(hash)
  end


  def establish_class
    puts generate_code
    if template_class
      begin
        eval generate_code
      rescue Exception => e
        warn e
      end
    else
      raise "No class name."
    end
  end

  def generate_code
    <<RUBY
class ::#{template_class} < TemplateInstance
  #{class_body.join("\n").split("\n").join("\n  ")}
end
RUBY
  end

  def class_body
    body = []
    children.each { |ch|
      if (ch.respond_to? :class_body) && (use_meta_creator ch)
        body << ch.class_body
      end
    }
    body
  end

  class Test < FwTest
    def test_generate_bare_class
      DataMapper.setup(:test, :adapter => 'in_memory')
      repository(:test) {
        c = ContentTemplate.new
        c.template_class = 'Megazord'
        definition = c.generate_code.
          match(/^\s*class ::(\S*) < (\S*)\s*end\s*$/)
        eq definition[1], 'Megazord'
        eq definition[2], 'TemplateInstance'
      }
    end

    def test_saving_establishes_class
      DataMapper.setup(:test, :adapter => 'in_memory')
      repository(:test) {
        c = ContentTemplate.new
        c.template_class = 'Ultrazord'
        c.save
        Module.constants.include? 'Ultrazord'
      }
    end
  end


  class TemplateInstance < ContentWithFields
    property :template_version, String

    def creator e
      auto_migrate
      super
    end

    def recieve e
      auto_migrate
      super
    end

    def auto_migrate
      template.content_children.each { |child|
        if !children.select { |ch|
              (ch.respond_to? :name) &&
              (ch.name == child.name)
          }.first
          add Thing.from_hash(child.to_hash, self)
        end
      }
      self
    end

    def template
      @template ||= ContentTemplate.first(:template_class => self.class)
    end

    class Test < FwTest
      def test_templateinstance_finds_its_template
        DataMapper.setup(:test, :adapter => 'in_memory')
        repository(:test) {
          cat_template = ContentTemplate.new()
          cat_template.template_class = 'LuckyCatWearingHat'
          cat_template.save

          template_instance = cat_template.clone_thing
          eq template_instance.template, cat_template
        }
      end

      def test_auto_migrate_missing_field
        DataMapper.setup(:test, :adapter => 'in_memory')
        repository(:test) {
          cat_template = ContentTemplate.new()
          cat_template.template_class = 'LuckyCatWearingHat'
          cat_template.save

          cat = cat_template.clone_thing

          cat_template.add StringField.new(:name)
          cat_template.save

          eq cat.children.length, 0
          cat.auto_migrate
          eq cat.children.length, 1
        }
      end

      def test_clone_thing_assigns_children
        DataMapper.setup(:test, :adapter => 'in_memory')
        repository(:test) {
          hat_template = ContentTemplate.new()
          hat_template.template_class = 'HatWearingCat'
          hat_template.add StringField.new(:name)
          hat_template.save

          hat = hat_template.clone_thing

          eq hat.children.length, 1
        }
      end

      def test_auto_migrate_does_not_add_already_used_fields
        DataMapper.setup(:test, :adapter => 'in_memory')
        repository(:test) {
          hat_template = ContentTemplate.new()
          hat_template.template_class = 'HatWearingCat'
          hat_template.add StringField.new(:name)
          hat_template.save

          hat = hat_template.clone_thing

          hat.auto_migrate
          eq hat.children.length, 1
        }
      end
    end
  end

end
